import time

import scrapy

import json

from JD.items import JdItem

import re


class BookSpider (scrapy.Spider):
    name = 'book'
    # 修改允许的域
    allowed_domains = ['jd.com']
    # 修改起始的url
    start_urls = ['https://pjapi.jd.com/book/sort?source=bookSort']

    # 起始的京东所有图书分类是通过ajax动态加载的所以在页面上搜寻不到所以只能通过
    # 请求接口来获取所有的图书分类信息和对应的编号用于下面的请求拼接
    # 此请求接口直接输入接口地址或者去用页面当时加载的页面接口参数去请求是会被认为
    # 是非法请求如果想要知道如何请求接口请看JD下面的text.py去看相应的伪装过程
    # 当然也可以去pipelines.py里去看当然没text.py里详细
    def parse(self, response):
        # print(response.body.decode())#如果请求成功返回就是json格式用json模块解析
        big_dict = json.loads (response.body.decode ())
        for big_node in big_dict['data']:  # 对返回内容中的data进行遍历
            for small_node in big_node['sonList']:
                item = JdItem ()
                item['big_category'] = big_node['categoryName']  # 获取data中大分类的名字赋值给item
                # 因为大分类的链接点进去之后可以看出是https://channel.jd.com/1713-3258.html格式的可以看出
                # 是由大分类中的fatherCategoryId: 1713和大分类本身的id拼接而成因为我爬的是图书所以大分类中的
                # 的fatherCategoryId一直不会变所以图省事直接1713写死了后面再加上大分类本身的id就完成了
                item['big_category_link'] = 'https://channel.jd.com/1713-' + str (
                    int (big_node['categoryId'])) + '.html'

                item['small_category'] = small_node['categoryName']
                # 再找到大分类中的小分类的名字赋值给small_category
                item['small_category_link'] = "https://list.jd.com/list.html?cat=1713," + str (
                    int (big_node['categoryId'])) + "," + str (int (small_node['categoryId'])) + '&page=1'
                # 小分类的链接就是大分类的father的id加上小分类的id再加上图书本身的id就行了
                # 如果不加&page=1拼接之后https://list.jd.com/list.html?cat=1713,3258,3297&page=1请求的默认也是第一页
                # 因为下面的翻页需要这里还是添加上page=1这个参数
                # https://list.jd.com/list.html?cat=1713,3258,3297&page=1 小分类的完整链接（样例）
                # 再为所有的小分类链接创建请求并且跳转到parse_detail这个解析函数再用meta将详细item项目传输过去
                yield scrapy.Request (
                    # url=item['small_category_link'],
                    url=item['small_category_link'],
                    callback=self.parse_detail,
                    meta={'item': item,
                          'dont_redirect': True,
                          'handle_httpstatus_list': [302]

                          }
                )

    def parse_detail(self, response):
        # 接收到parse传过来的item信息
        # 里面包含着大小分类的名字和链接
        item = response.meta['item']
        books_list = response.xpath ("//*[@id='J_goodsList']/ul/li")
        # 查看小分类链接里所有的图书信息都是由ul下面的li标签排列而成的所以就先获取所有的li标签
        # 通过查看页面后得知翻页是没有对应的url是通过js动态加载的
        # 但是通过对于翻页前后网址的对比可以看出从翻页操作是通过page+=2完成的
        # 也就是说只要改变page的值就能实现翻页效果不需要提取url（也没有url可以提取）
        # 下面就是判断当前页面中的图书也就是目标li的个数是不是60个
        # 泪崩。。图书是懒加载的得通过selenuim作为中间件渲染页面
        if len (books_list) == 0:
            print ("貌似被重定向")
            time.sleep(3)
            print("3秒后重新发起请求")
            yield scrapy.Request (
                url=response.url,
                callback=self.parse_detail,
                dont_filter=True,
                meta={'item': response.meta['item'],
                      'dont_redirect': True})
        # 如果是尾页的话就不满60个就会跳过这个判断不去创建请求
        if len (books_list) == 60:
            # https://list.jd.com/list.html?cat=1713,3258,3297&page=1 #例子url就是这样下面就是对url中的page进行累加操作最后再拼接
            list = re.split ("&", response.url)
            # 通过&分隔url
            str1 = str (int (re.findall ('\d+', list[1])[0]) + 2)
            # 提取第二个page中的数字再将其加2后转为字符串
            next_url = list[0] + '&page=' + str1
            # 拼接url
            print ("拼接下一页url", next_url)
            # 为url创建request请求将meta中的item对象传入
            # （如果不传入item对象翻页后会因为response取不到item对象而报错而不会去执行下面的代码）
            yield scrapy.Request (
                url=next_url,
                callback=self.parse_detail,
                dont_filter=True,
                meta={'item': response.meta['item'],
                      'dont_redirect': True,
                      'handle_httpstatus_list': [302]}
            )
        for book in books_list:
            # 下面就是开心的获取信息
            item['small_category_link'] = response.url
            # 这里要重置一下小分类链接因为翻页的缘故所以page的信息有所改变
            item['link'] = response.urljoin (book.xpath ("./div/div[@class='p-img']/a/@href").extract_first ())
            # 提取到每个图书的详情页链接
            item['bookname'] = book.xpath ("./div/div[@class='p-name']/a/em/text()").extract_first ()
            # 提取到每个图书的书名
            item['author'] = book.xpath (
                "./div/div[@class='p-bookdetails']/span[@class='p-bi-name']/a/text()").extract_first ()
            # 提取到每个图书的作者
            item['price'] = book.xpath ("./div/div[@class='p-price']/strong/i/text()").extract_first ()
            # 提取到每个图书的价格（跟之前比起来价格不是通过接口请求的而是直接加载到页面的省了一些功夫）
            yield item
            # 返回图书的信息
